<template>
  <div ref="container">
    <div>帧数：{{ framesPerSecond }}</div>
    <div id="displayPanel">
      <div class="buttonPanel">
        <div class="view-button">
          <div class="camera">
            <p class="title">摄像机位置</p>
            <p class="explain">*绿色圆形代表摄像机位置</p>
            <p class="explain">*下方拖动条为摄像机坐标</p>
            <div class="input-group">
              <div>
                <span> x：</span
                ><input
                  type="number"
                  class="posInput"
                  v-model="cameraPos.x"
                  min="-1000"
                  max="1000"
                />
              </div>

              <input
                type="range"
                v-model="cameraPos.x"
                min="-1000"
                max="1000"
              />
            </div>
            <div class="input-group">
              <div>
                <span> y：</span
                ><input
                  type="number"
                  class="posInput"
                  v-model="cameraPos.y"
                  min="-1000"
                  max="1000"
                />
              </div>

              <input
                type="range"
                v-model="cameraPos.y"
                min="-1000"
                max="1000"
              />
            </div>
            <div class="input-group">
              <div>
                <span> z：</span
                ><input
                  type="number"
                  class="posInput"
                  v-model="cameraPos.z"
                  min="-1000"
                  max="1000"
                />
              </div>

              <input
                type="range"
                v-model="cameraPos.z"
                min="-1000"
                max="1000"
              />
            </div>
            
          </div>
          <button @click="swithView">切换至{{ switchButtonText }}视角</button>
        </div>

        <div class="create-button">
          <div class="setting">
            <p class="title">模型规模</p>
            <p class="explain">*最底层模型规模，该规模会影响层级模型的构建</p>
            <div>横向数量：<input v-model="rowNumber" /></div>
            <div>纵向数量：<input v-model="columnNumber" /></div>
            <div>总量：{{ rowNumber * columnNumber }}</div>
          </div>
          <!-- <div class="setting">
            <p class="title">模型密度</p>
            <div>横向距离：<input v-model="rowSpace" /></div>
            <div>纵向距离：<input v-model="columnSpace" /></div>
          </div> -->
          <div class="setting">
            <p class="title">层级列表</p>
            <p class="explain">*最底层模型的上级层数，数量越大越多层</p>
            <div>
              中间层级总数：<input
                type="number"
                v-model.number="midLayersNum"
                @input="maxNumberInput"
              />
            </div>
          </div>
          <div class="setting">
            <p class="title">中间层级模型容纳量</p>
            <p class="explain">*层级模型对下层的容纳量</p>
            <div style="display: flex">
              <input
                type="radio"
                name="contain"
                value="unite"
                v-model="containMode"
              />
              <p>统一容纳量</p>
            </div>

            <div class="uniteModeSetting" v-show="this.containMode == 'unite'">
              <div>
                横向数量：<input type="number" v-model="rowChildNumber" />
              </div>
              <div>
                纵向数量：<input type="number" v-model="columnChildNumber" />
              </div>
              <div>总量：{{ rowChildNumber * columnChildNumber }}</div>
            </div>

            <div
              style="
                display: flex;
                user-select: none;
                pointer-events: none;
                opacity: 30%;
              "
            >
              <input
                type="radio"
                name="contain"
                value="divide"
                v-model="containMode"
              />
              <p>分层容纳量</p>
            </div>

            <div
              class="divideModeSetting"
              v-show="this.containMode == 'divide'"
            >
              <div v-for="(obj, key) of layersChildNumber" :key="key">
                <div>第{{ key + 1 }}层级</div>
                <div>
                  横向数量：<input type="number" v-model="obj.rowChildNumber" />
                </div>
                <div>
                  纵向数量：<input
                    type="number"
                    v-model="obj.columnChildNumber"
                  />
                </div>
                <div>
                  总量：{{ obj.rowChildNumber * obj.columnChildNumber }}
                </div>
              </div>
            </div>
          </div>
          <div class="setting">
            <p class="title">观察距离设置</p>
            <div style="
                user-select: none;
                pointer-events: none;
                opacity: 30%;
              ">
              <div v-for="(entity, key) of watchDistance">
                LOD{{ key + 1 }}模型的最小观测距离：
                <input
                  style="width: 60px"
                  type="number"
                  v-model="entity.distance"
                />
              </div>
              <div>
                LODmax模型的最小观测距离：<input
                  style="width: 60px"
                  type="number"
                  v-model="watchDistanceMax"
                />
              </div>
            </div>
            <p class="explain">*如果你无法理解，可以尝试从上至下依次输入：4,4,2,2,2；输入完毕后点击下方按钮</p>
            <button @click="requestTestCity" class="createTestButton">创建层级模型</button>
          </div>

          
        </div>
        
        <!-- <button>只看底层</button> -->
        <button @click="testParent">测试</button>
      </div>

      <div ref="canvas"></div>
      <div class="EntityList">
        <span>实体模型列表</span>
        <div v-for="entity of cimList" :key="entity.id" class="entityInList">
          <div>实体名：{{ entity.entityName }}</div>
          <div>实体id：{{ entity.id }}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import axios from "axios";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader.js";
import { MTLLoader } from "three/examples/jsm/loaders/MTLLoader.js";
import CimScene from "../assets/class/CimScene";
import { initializeScene } from "../assets/class/CimLod";

let scene = "";

let renderer = "";
let controls = "";
export default {
  data() {
    return {
      //三维相关
      camera: "",
      light: "",
      directionalLight: "",
      width: window.innerWidth * 0.67,
      height: window.innerHeight * 0.9,
      lightHelper: "",
      frames: 0,
      times: 0,
      framesPerSecond: 0,
      clock: "",

      //场景相关
      cimScene: "",
      cimList: [],
      cameraPos: { x: 0, y: 0, z: 0 },
      //视角相关
      viewMode:"third",
      switchButtonText:"第一人称",

      //设置面板相关
      rowNumber: 1,
      columnNumber: 1,
      rowSpace: 10,
      columnSpace: 10,
      midLayersNum: 0,
      //选择的容纳模式
      containMode: "unite",
      //统一容纳量
      rowChildNumber: 1,
      columnChildNumber: 1,
      //分层容纳量
      layersChildNumber: [],
      //观察距离设置
      watchDistance: [],
      watchDistanceMax: 100,
    };
  },
  watch: {
    cameraPos: {
      handler() {
        //更新模型显示
        let newList = initializeScene(this.cameraPos, this.cimScene, 0);

        let addList = newList
          .filter(
            (itemNew) =>
              !this.cimList.some((itemOld) => itemNew.id === itemOld.id)
          )
          .slice();
        let deleteList = this.cimList
          .filter(
            (itemOld) => !newList.some((itemNew) => itemNew.id === itemOld.id)
          )
          .slice();

        deleteList.forEach((cimEntity) => {
          cimEntity.removeModel(scene);
        });

        addList.forEach((cimEntity) => {
          cimEntity.addModel(scene);
        });

        this.cimList = newList;

        //更新摄像机位置
        let watch = scene.getObjectByName("观察体-");
        watch.position.set(
          this.cameraPos.x,
          this.cameraPos.y,
          this.cameraPos.z
        );
      },
      deep: true,
    },
    "camera.position": {
      handler() {
        if (this.viewMode == "first") {
          //修改视角
          this.cameraPos.x = this.camera.position.x;
          this.cameraPos.y = this.camera.position.y;
          this.cameraPos.z = this.camera.position.z;
        }
      },
      deep: true,
      immediate:true
    },
    midLayersNum: {
      handler(newValue, oldValue) {
        if (newValue > oldValue) {
          //添加
          while (oldValue < newValue) {
            oldValue++;
            this.layersChildNumber.push({
              rowChildNumber: 1,
              columnChildNumber: 1,
            });
            this.watchDistance.push({
              distance: 100,
            });
          }
        } else {
          while (oldValue > newValue) {
            this.layersChildNumber.pop();
            this.watchDistance.pop();
            oldValue--;
          }
        }
      },
      immediate: true,
    },
  },
  async mounted() {
    THREE.Cache.enabled = true;
    //初始值
    this.cimScene = await this.createCimScene();
    //创建threejs中的场景、相机、渲染器
    let cim = this.cimScene.createScene(this.width, this.height);
    scene = cim.scene;
    this.camera = cim.camera;
    renderer = cim.renderer;

    //模型初次加载
    this.cimList = initializeScene(this.cameraPos, this.cimScene, 0);
    this.cimList.forEach((cimEntity) => {
      cimEntity.addModel(scene);
    });

    //摄像机位置设置
    this.loadObj(
      "观察体",
      "观察体",
      this.cameraPos.x,
      this.cameraPos.y,
      this.cameraPos.z
    );

    //地板
    this.loadObj("floor", "floor", 0, -3, 0);

    console.log(scene);

    while (this.$refs.canvas.firstChild) {
      this.$refs.canvas.removeChild(this.$refs.canvas.firstChild);
    }
    this.$refs.canvas.appendChild(renderer.domElement);
    controls = new OrbitControls(this.camera, renderer.domElement); //创建控件对象
    controls.mouseButtons = {
      LEFT: THREE.MOUSE.PAN,
      MIDDLE: THREE.MOUSE.DOLLY,
      RIGHT: THREE.MOUSE.ROTATE,
    };

    this.clock = new THREE.Clock();

    this.animate();
  },
  methods: {
    animate() {
      renderer.render(scene, this.camera);
      this.frames = this.frames + 1;
      let T = this.clock.getDelta();
      this.times = this.times + T;
      if (this.times >= 1) {
        this.framesPerSecond = Math.floor(this.frames / this.times);
        this.frames = 0;
        this.times = 0;
      }
      requestAnimationFrame(this.animate); //请求再次执行渲染函数render
    },

    loadObj(objname, mtlname, x, y, z) {
      var loader = new OBJLoader();
      var mloader = new MTLLoader();
      const cityGroup = new THREE.Object3D();
      cityGroup.name = objname;
      mloader.load("static/lodModel/" + mtlname + ".mtl", function (materials) {
        materials.preload();
        loader.setMaterials(materials);
        loader.load(
          "static/lodModel/" + objname + ".obj",
          function loadobj(obj) {
            obj.name = objname + "-";
            if(objname=="观察体"){
              obj.scale.set(0.4,0.4,0.4)
            }
            cityGroup.add(obj);
            cityGroup.position.set(x, y, z);
          }
        );
      });
      renderer.render(scene, this.camera);
      scene.add(cityGroup);
    },

    async createCimScene() {
      let configData = await axios.get("/lod/random333-city").then(
        (response) => {
          // 请求成功时的处理
          console.log("成功获取数据");
          return response.data;
        },
        (error) => {
          // 请求失败时的处理
          console.error("获取数据失败:", error);

          return this.getLocalData();
        }
      );

      console.log(configData);
      let configScene = configData.scene;

      //创建数据结构的scene
      let cimScene = new CimScene("scene_0001", {
        name: configScene.name,
        lodsetting: configScene.lodsetting,
        default_camera: configScene.default_camera,
        default_background: configScene.default_background,
        children: configScene.children,
      });
      cimScene.loadEntity();
      console.log("cimScene", cimScene);

      return cimScene;
    },

    async requestTestCity() {
      const requestData = {
        rowNumber: this.rowNumber,
        columnNumber: this.columnNumber,
        rowSpace: this.rowSpace,
        columnSpace: this.columnSpace,
        midLayersNum: this.midLayersNum,
        containMode: this.containMode,
        watchDistance: this.watchDistance,
        watchDistanceMax: this.watchDistanceMax,
      };
      if (this.containMode == "unite") {
        requestData.rowChildNumber = this.rowChildNumber;
        requestData.columnChildNumber = this.columnChildNumber;
      } else {
        requestData.layersChildNumber = this.layersChildNumber;
      }
      let testData = await axios.post("/lod/new-test-city", requestData).then(
        (response) => {
          console.log("提交成功！", response.data);
          return response.data;
        },
        (error) => {
          console.log(error.message);
          alert("提交失败！请排除原因");
        }
      );

      let configScene = testData.scene;
      //创建数据结构的scene
      this.cimScene = new CimScene("scene_0001", {
        name: configScene.name,
        lodsetting: configScene.lodsetting,
        default_camera: configScene.default_camera,
        default_background: configScene.default_background,
        children: configScene.children,
      });
      this.cimScene.loadEntity();
      //模型再次加载
      this.clearScene();
      this.cimList = initializeScene(this.cameraPos, this.cimScene, 0);
      this.cimList.forEach((cimEntity) => {
        cimEntity.addModel(scene);
      });
    },

    async getLocalData() {
      let localData = await fetch("static/localTest.json").then(
        (res) => {
          return res.json();
        },
        (err) => {
          console.log("本地json错误：" + err);
        }
      );

      return localData;
    },

    //清空场景模型
    clearScene() {
      this.cimList.forEach((cimEntity) => {
        cimEntity.removeModel(scene);
      });
    },

    async requestRandomCity() {
      let localData = await axios.get("/lod/random-city333").then(
        (response) => {
          //刷新内容，这里先用浏览器重刷
          //window.location.reload(true);
          console.log("刷新后数据", response.data);
          return response.data;
        },
        (error) => {
          console.log(error.message);
          alert("无法连接至服务器，即将刷新页面");
          //刷新内容，这里先用浏览器重刷
          window.location.reload(true);
        }
      );

      let configScene = localData.scene;

      //创建数据结构的scene
      this.cimScene = new CimScene("scene_0001", {
        name: configScene.name,
        lodsetting: configScene.lodsetting,
        default_camera: configScene.default_camera,
        default_background: configScene.default_background,
        children: configScene.children,
      });
      this.cimScene.loadEntity();
      console.log("cimScene", this.cimScene);
      //模型再次加载
      this.clearScene();
      this.cimList = initializeScene(this.cameraPos, this.cimScene, 0);
      this.cimList.forEach((cimEntity) => {
        cimEntity.addModel(scene);
      });
    },

    //限制层级数量
    maxNumberInput() {
      if (this.midLayersNum > 10) {
        this.midLayersNum = 10;
      } else if (this.midLayersNum < 0) {
        this.midLayersNum = 0;
      }
    },

    //切换视角
    swithView(){
      if(this.viewMode == "first"){
        this.viewMode = "third"
        this.cameraPos.x = 0;
        this.cameraPos.y = 0;
        this.cameraPos.z = 0;
        this.switchButtonText = "第一人称"
      }else if(this.viewMode == "third"){
        this.viewMode = "first"
        this.switchButtonText = "第三人称"
        //调整模拟摄像机的位置
        this.camera.position.x++;
        this.camera.position.y++;
        this.camera.position.z++;
      }
    },

    testParent() {
      let a = this.cimList[0];
      console.log('删除对象',a);
      a.deleteEntity();
      this.cameraPos = { x: 0, y: 0, z: 0 };
    },
  },
  beforeDestroy() {
    //销毁内存中的模型
    THREE.Cache.clear();
  },
};
</script>

<style>
#displayPanel {
  display: flex;
}
.buttonPanel {
  display: flex;
  flex-direction: column;
  width: 20vw;
  height: 95vh;

  margin-right: 10px;
  overflow-y: scroll;
  overflow-x: hidden;
}

.view-button {
  border: solid 3px brown;
  border-radius: 5px;
  padding: 0 5px 20px 5px;
  background-color: #7ba4f799;
  margin: 0 0 20px 0;
}

.camera {
  width: 80%;
}

.create-button {
  border: solid 3px brown;
  border-radius: 5px;
  padding: 0 5px 20px 5px;
  background-color: #cfdfff99;
  margin: 0 0 20px 0;
}

.create-button input {
  width: 100px;
}

.create-button input[type="radio"] {
  width: 20px;
}

.title {
  text-decoration: underline;
  font-size: 20px;
  font-weight: bolder;
}

.explain{
  color: rgb(106, 70, 2);
  font-weight: 600;
}

.divideModeSetting {
  height: 300px;
  overflow-y: scroll;
  overflow-x: hidden;
  border: solid 2px black;
}

.input-group {
  margin-right: 20px;
  text-align: center;
  display: flex;
  flex-direction: column;
}

.EntityList {
  width: 13vw;
  height: 90vh;
  overflow-y: scroll;
  overflow-x: hidden;
}

.EntityList .entityInList {
  border: solid 2px rgb(124, 124, 227);
  border-radius: 6px;
  padding: 3px 5px 3px 5px;
}

.createTestButton{
  height: 100px;
  width:200px;
  font-size: 20px;
  margin-top: 20px;
}
</style>